/**
 * gntxmms - An XMMS2 client based on libgnt.
 *
 * Copyright 2007, Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer 
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <gnt.h>
#include <gntbox.h>
#include <gntbutton.h>
#include <gntentry.h>
#include <gntfilesel.h>
#include <gntlabel.h>
#include <gntline.h>
#include <gnttree.h>
#include <gntwindow.h>

#include "gntxmms.h"
#include "gxplaylist.h"
#include "utils.h"

static xmmsc_connection_t *conn;
GHashTable *songs;  /* XXX: This is somewhat unfortunate */

static struct {
	GntWidget *win;
	GntWidget *info;
	GxPlayList *list;
} playlist;

static void update_status(xmmsc_result_t *res, gpointer null);

static void
update_tag(const char *tag, const char *text)
{
	gnt_text_view_tag_change(GNT_TEXT_VIEW(playlist.info), tag, (text && *text) ? text : "--", TRUE);
}

static void
update_current_song()
{
	xmmsc_result_t *res;

	res = xmmsc_playlist_current_pos(conn, NULL);
	xmmsc_result_wait(res);
	if (!xmmsc_result_get_uint(res, &playlist.list->current.pos))
		return;   /* XXX: is res leaking? */
	xmmsc_result_unref(res);
	playlist.list->current.info = g_list_nth_data(playlist.list->songs, playlist.list->current.pos);
	if (!playlist.list->current.info)
		return;

	gnt_tree_set_row_flags(GNT_TREE(playlist.list), GINT_TO_POINTER(playlist.list->current.pos + 1), GNT_TEXT_FLAG_BOLD);
	update_tag("artist", playlist.list->current.info->artist);
	update_tag("title", playlist.list->current.info->title);
	update_tag("url", playlist.list->current.info->url);

	res = xmmsc_playback_status(conn);
	update_status(res, NULL);
}

/*******
 * Callbacks from xmms *
 */
static void
update_playtime(xmmsc_result_t *res, gpointer null)
{
	xmmsc_result_t *newr;
	long int time;
	char text[256];
	int perc, wid;

	xmmsc_result_get_uint(res, &time);
	if (!playlist.list->current.info)
		update_current_song();
	snprintf(text, sizeof(text), "%02ld:%02ld/%02ld:%02ld", time/60000, (time / 1000) % 60,
			playlist.list->current.info->duration/60000, (playlist.list->current.info->duration / 1000) % 60);
	gnt_text_view_tag_change(GNT_TEXT_VIEW(playlist.info), "duration", text, TRUE);

	gnt_widget_get_size(playlist.info, &wid, NULL);
	wid -= 12;
	perc = time * wid / playlist.list->current.info->duration;
	text[wid + 1] = '\0';
	while (wid > perc)
		text[wid--] = '-';
	text[perc--] = '|';
	while (perc >= 0)
		text[perc--] = '=';
	gnt_text_view_tag_change(GNT_TEXT_VIEW(playlist.info), "progress", text, TRUE);

	gnt_widget_draw(playlist.info);

	/* This is necessary to keep the 'timer' going */
    newr = xmmsc_result_restart(res);
    xmmsc_result_unref(res);
    xmmsc_result_unref(newr);
}

static void
update_name(xmmsc_result_t *result, gpointer null)
{
	unsigned int id;

	xmmsc_result_wait(result);
	xmmsc_result_get_uint(result, &id);
	if (playlist.list->current.info)
		gnt_tree_set_row_flags(GNT_TREE(playlist.list),
					GINT_TO_POINTER(playlist.list->current.pos + 1), GNT_TEXT_FLAG_NORMAL);
	update_current_song();
}

static void
update_status(xmmsc_result_t *res, gpointer null)
{
	unsigned int status;
	const char *text = "...";

	xmmsc_result_wait(res);
	xmmsc_result_get_uint(res, &status);
	switch (status) {
		case XMMS_PLAYBACK_STATUS_STOP:
			text = "Stopped  ";
			break;
		case XMMS_PLAYBACK_STATUS_PLAY:
			text = "Playing  ";
			break;
		case XMMS_PLAYBACK_STATUS_PAUSE:
			text = "Paused   ";
			break;
	}
	gnt_text_view_tag_change(GNT_TEXT_VIEW(playlist.info), "status", text, TRUE);
	gnt_widget_draw(playlist.info);
}

static void
dict_foreach(const void *key, xmmsc_result_value_type_t type, const void *value, void *null)
{
	g_printerr("%s %d %p\n", key, type, value);
}

static void
update_playlist(xmmsc_result_t *t, gpointer null)
{
	xmmsc_result_dict_foreach(t, dict_foreach, null);
	gx_playlist_update(playlist.list);
}

/*******
 * Callbacks for Add File *
 */
static void
add_file_select_cb(GntWidget *wid, GntFileSel *filesel)
{
	char *sel = gnt_file_sel_get_selected_file(filesel);
	gx_add(sel, FALSE);
	g_free(sel);
	gnt_widget_destroy(GNT_WIDGET(filesel));
}

static void
add_file_clicked(GntWidget *wid, gpointer null)
{
	GntFileSel *filesel = GNT_FILE_SEL(gnt_file_sel_new());
	gnt_file_sel_set_current_location(filesel, "");
	gnt_box_set_title(GNT_BOX(filesel), "Add File");
	g_signal_connect(G_OBJECT(filesel->select), "activate", G_CALLBACK(add_file_select_cb), filesel);
	g_signal_connect_swapped(G_OBJECT(filesel->cancel), "activate",
			G_CALLBACK(gnt_widget_destroy), filesel);
	gnt_widget_show(GNT_WIDGET(filesel));
}

#if 0
/*******
 * Callbacks for Add URL *
 */
static void
add_url_clicked(GntWidget *wid, gpointer null)
{
}
#endif

/*******
 * Callbacks for Add Dir *
 */
static void
add_dir_select_cb(GntWidget *wid, GntFileSel *filesel)
{
	char *sel = gnt_file_sel_get_selected_file(filesel);
	gx_add(sel, TRUE);
	g_free(sel);
	gnt_widget_destroy(GNT_WIDGET(filesel));
}

static void
add_dir_clicked(GntWidget *wid, gpointer null)
{
	GntFileSel *filesel = GNT_FILE_SEL(gnt_file_sel_new());
	gnt_file_sel_set_current_location(filesel, "");
	gnt_file_sel_set_dirs_only(filesel, TRUE);
	gnt_box_set_title(GNT_BOX(filesel), "Add Directory");
	g_signal_connect(G_OBJECT(filesel->select), "activate", G_CALLBACK(add_dir_select_cb), filesel);
	g_signal_connect_swapped(G_OBJECT(filesel->cancel), "activate",
			G_CALLBACK(gnt_widget_destroy), filesel);
	gnt_widget_show(GNT_WIDGET(filesel));
}

int main()
{
	GntWidget *win, *list, *tv;
	GntWidget *hbox, *button;

	if (!(conn = gx_init()))
		return 1;

	songs = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify)gx_song_info_unref);

	freopen(".error", "w", stderr);
	gnt_init();

	playlist.win = win = gnt_vwindow_new(FALSE);
	gnt_box_set_title(GNT_BOX(win), "GntXMMS2");
	gnt_box_set_pad(GNT_BOX(win), 0);
	gnt_box_set_alignment(GNT_BOX(win), GNT_ALIGN_MID);

	/* Info panel */
	playlist.info = tv = gnt_text_view_new();
	gnt_box_add_widget(GNT_BOX(win), tv);
	gnt_widget_set_size(tv, -1, 5);
#define ADD_FIELD(name, tag) \
	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), name, GNT_TEXT_FLAG_BOLD); \
	gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(tv), "...", GNT_TEXT_FLAG_NORMAL, tag); \
	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), "\n", GNT_TEXT_FLAG_NORMAL);

	ADD_FIELD("Title: ", "title");
	ADD_FIELD("Artist: ", "artist");
	ADD_FIELD("Duration: ", "duration");
	ADD_FIELD("URL: ", "url");
	gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(tv), " ", GNT_TEXT_FLAG_BOLD, "status");
	gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(tv), " ", GNT_TEXT_FLAG_NORMAL, "progress");
	gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0);

	gnt_box_add_widget(GNT_BOX(win), gnt_hline_new());

	/* Playlist */
	playlist.list = GX_PLAY_LIST(list = gx_playlist_new(NULL));
	gnt_box_add_widget(GNT_BOX(win), list);

	gnt_box_add_widget(GNT_BOX(win), gnt_hline_new());

	/* Buttons */
	hbox = gnt_hbox_new(TRUE);

	button = gnt_button_new("Add File");
	g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_file_clicked), NULL);
	gnt_box_add_widget(GNT_BOX(hbox), button);

#if 0
	button = gnt_button_new("Add URL");
	g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_url_clicked), NULL);
	gnt_box_add_widget(GNT_BOX(hbox), button);
#endif

	button = gnt_button_new("Add Dir");
	g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_dir_clicked), NULL);
	gnt_box_add_widget(GNT_BOX(hbox), button);

	gnt_box_add_widget(GNT_BOX(win), hbox);

	gnt_widget_show(win);
	gx_playlist_update(playlist.list);

	/* Get info about the current song, if any */
	update_current_song();

	/* Setup the connections */
	XMMS_CALLBACK_SET(conn, xmmsc_signal_playback_playtime, 
			update_playtime, NULL);
	XMMS_CALLBACK_SET(conn, xmmsc_broadcast_playback_current_id, 
			update_name, conn);
	XMMS_CALLBACK_SET(conn, xmmsc_broadcast_playback_status,
			update_status, conn);
	XMMS_CALLBACK_SET(conn, xmmsc_broadcast_playlist_changed, 
			update_playlist, conn);

	gnt_main();
	xmmsc_disconnect_callback_set(conn, NULL, NULL);
	xmmsc_unref(conn);

	gnt_quit();
	return 0;
}

